<?php

namespace yunj\app\admin\service\route\page;

use think\db\BaseQuery;
use think\db\Query;
use think\facade\Db;
use think\Route;
use yunj\app\admin\enum\EnableLoginAuth;
use yunj\app\admin\enum\IsDemo;
use yunj\app\admin\enum\IsSystem;
use yunj\app\admin\enum\route\RequestMethod;
use yunj\app\admin\enum\route\RouteDataType;
use yunj\app\admin\enum\route\RoutePageFormType;
use yunj\app\admin\enum\State;
use yunj\app\admin\service\route\RouteRequestService;
use yunj\app\admin\service\route\RouteService;
use yunj\app\admin\service\route\RouteSyncSystemDataService;
use yunj\app\admin\service\route\Service;
use yunj\core\builder\YunjForm;
use yunj\core\builder\YunjTable;
use yunj\core\enum\RedisKeyPrefixEnum;
use yunj\app\admin\enum\TableBuilderEvent;
use yunj\app\admin\validate\route\RouteValidate;
use yunj\core\enum\TipsTemplet;
use yunj\core\response\Json;
use yunj\core\response\SuccessJson;

class RouteListService extends Service {

    /**
     * 获取列表构建器
     * @return YunjTable
     */
    public function getListBuilder(): YunjTable {
        $args = [
            'state' => State::getTableBuilderState(),
            'filter' => function (YunjTable $builder, $state) {
                return [
                    'keywords' => [
                        'title' => '关键词',
                        'placeholder' => '描述/规则/地址/URI',
                        'auth' => 'yunj_route_list_filter_keywords',
                    ],
                ];
            },
            'toolbar' => function (YunjTable $builder, $state) {
                $toolbar = [
                    'groupAdd' => ['type' => 'openPopup', 'title' => '添加分组', 'class' => 'layui-icon-add-circle', 'url' => build_url('yunjAdminRouteAdd', ['type' => RouteDataType::GROUP]), 'auth' => 'yunj_route_add'],
                    'routeAdd' => ['type' => 'openPopup', 'title' => '添加路由', 'class' => 'layui-icon-add-circle', 'url' => build_url('yunjAdminRouteAdd', ['type' => RouteDataType::ROUTE]), 'auth' => 'yunj_route_add']
                ];
                switch ($state) {
                    case State::NORMAL:
                        $toolbar += [
                            TableBuilderEvent::SORT => ['title' => '树形/排序', 'type' => 'openPopup', 'class' => 'yunj-icon-sort',
                                'url' => build_url('yunjAdminRouteSort'), 'auth' => 'yunj_route_sort'],
                            TableBuilderEvent::RECYLE_BIN => ['title' => '移入回收站', 'type' => 'asyncEvent', 'dropdown' => true, 'auth' => 'yunj_route_recyle_bin'],
                        ];
                        break;
                    case State::RECYLE_BIN:
                        $toolbar += [
                            TableBuilderEvent::NORMAL => ['title' => '恢复正常', 'type' => 'asyncEvent', 'dropdown' => true, 'auth' => 'yunj_route_normal'],
                            TableBuilderEvent::DELETED => ['title' => '永久删除', 'type' => 'asyncEvent', 'dropdown' => true, 'auth' => 'yunj_route_deleted'],
                        ];
                        break;
                }
                return $toolbar;
            },
            'defaultToolbar' => function (YunjTable $builder, $state) {
                $defaultToolbar = [
                    'filter',
                    'export' => [
                        'auth' => 'yunj_route_export'
                    ],
                    'syncSystemDatas' => [
                        'title' => '同步系统路由数据',
                        'type' => 'asyncEvent',
                        'class' => 'yunj-icon-refresh',
                        'auth' => 'yunj_route_sync_system_datas'
                    ],
                    'clearCache' => [
                        'title' => '清理缓存',
                        'type' => 'asyncEvent',
                        'class' => 'yunj-icon-clear',
                        'auth' => 'yunj_route_clear_cache'
                    ]
                ];
                return $defaultToolbar;
            },
            "page" => function (YunjTable $builder, $state) {
                // 回收站开启分页
                return $state == State::RECYLE_BIN;
            },
            'tree' => function (YunjTable $builder, $state) {
                // 回收站不使用树形展示
                return $state != State::RECYLE_BIN;
            },
            'cols' => function (YunjTable $builder, $state) {
                $cols = [
                    'id' => ['type' => 'checkbox'],
                    'type' => ['type' => 'data'],
                    'name' => ['title' => '路由规则'],
                    'desc' => ['title' => '描述'],
                    'route' => ['title' => '路由地址'],
                    'url' => ['title' => 'URI'],
                    'middleware' => ['title' => '中间件', 'templet' => 'json', 'hide' => true],
                    'is_system' => ['title' => '系统配置', 'templet' => 'enum', 'align' => 'center', 'options' => IsSystem::getEnumOptions()],
                    'action' => ['title' => '操作', 'templet' => 'action', 'options' => []]
                ];
                $actionOptions = [
                    'groupAdd' => ['type' => 'openPopup', 'title' => '添加分组', 'class' => 'layui-icon-add-circle', 'url' => build_url('yunjAdminRouteAdd', ['type' => RouteDataType::GROUP]), 'show' => "d.type == '" . RouteDataType::GROUP . "' && d.is_system != " . IsSystem::YES, 'auth' => 'yunj_route_add'],
                    'routeAdd' => ['type' => 'openPopup', 'title' => '添加路由', 'class' => 'layui-icon-add-circle', 'url' => build_url('yunjAdminRouteAdd', ['type' => RouteDataType::ROUTE]), 'show' => "d.type == '" . RouteDataType::GROUP . "' && d.is_system != " . IsSystem::YES, 'auth' => 'yunj_route_add'],
                    'requestAdd' => ['type' => 'openPopup', 'title' => '添加请求项', 'class' => 'layui-icon-add-circle', 'url' => build_url('yunjAdminRouteAdd', ['type' => RouteDataType::REQUEST]), 'show' => "d.type == '" . RouteDataType::ROUTE . "' && d.is_system != " . IsSystem::YES, 'auth' => 'yunj_route_add'],
                    'edit' => ['type' => 'openPopup', 'title' => '详情', 'class' => 'layui-icon-survey', 'url' => build_url('yunjAdminRouteEdit'), 'auth' => 'yunj_route_edit'],
                ];
                switch ($state) {
                    case State::NORMAL:
                        $actionOptions += [
                            TableBuilderEvent::RECYLE_BIN => ['title' => '移入回收站', 'type' => 'asyncEvent', 'dropdown' => true, 'show' => "d.is_system != " . IsSystem::YES, 'auth' => 'yunj_route_recyle_bin'],
                        ];
                        break;
                    case State::RECYLE_BIN:
                        $actionOptions += [
                            TableBuilderEvent::NORMAL => ['title' => '恢复正常', 'type' => 'asyncEvent', 'dropdown' => true, 'show' => "d.is_system != " . IsSystem::YES, 'auth' => 'yunj_route_normal'],
                            TableBuilderEvent::DELETED => ['title' => '永久删除', 'type' => 'asyncEvent', 'dropdown' => true, 'show' => "d.is_system != " . IsSystem::YES, 'auth' => 'yunj_route_deleted']
                        ];
                        break;
                }
                $cols['action']['options'] = $actionOptions;
                $this->setListBuilderColsAuth($cols);
                return $cols;
            },
            'validate' => RouteValidate::class,
            'count' => function (YunjTable $builder, array $filter) {
                $where = self::getListBuilderFilterWhere($filter);
                return self::getListBuilderQuery()->where($where)->count();
            },
            'items' => function (YunjTable $builder, int $page, int $pageSize, array $filter, array $sort) {
                $where = self::getListBuilderFilterWhere($filter);
                $order = ['sort' => 'asc', 'id' => 'asc'];
                $items = self::getListBuilderQuery()->where($where)->order($order);
                if ($filter['state'] == State::RECYLE_BIN) {
                    $items->limit(($page - 1) * $pageSize, $pageSize);
                }
                $items = $items->select();
                $items = $items ? $items->toArray() : [];
                $this->handleListItems($items);
                return $items;
            },
            'event' => function (YunjTable $builder, $event, array $ids) {
                return $this->handleListBuilderEvent($builder, $event, $ids);
            },
        ];
        return YT('RouteList', $args);
    }

    // 处理异步事件
    private function handleListBuilderEvent(YunjTable $builder, $event, array $ids) {
        $data = $builder->getValidate()->getData();
        // 状态处理
        /** @var TableBuilderEvent|null $eventObj */
        $eventObj = $data['eventObj'] ?? null;
        if ($eventObj && $eventObj->isStateEvent()) {
            $data = $builder->getValidate()->getData();
            $this->handleListBuilderEventByState($eventObj, $data['dataTypes']);
            return success_json(['reload' => true]);
        }
        // 同步系统路由数据
        if ($event == 'syncSystemDatas') {
            RouteSyncSystemDataService::handle();
            return success_json(['reload' => true], '同步系统路由数据成功');
        }
        // 清理缓存
        if ($event == 'clearCache') {
            RouteRequestService::clearCache();
            return success_json(['reload' => true], '缓存清理成功');
        }
        return error_json("异常事件[{$event}]");
    }

    // 处理状态调整的异步事件
    private function handleListBuilderEventByState(TableBuilderEvent $eventObj, array $dataTypes) {
        if (request_not_confirmed()) {
            throw_confirm_json("确认" . $eventObj->getDesc() . "？");
        }
        $event = $eventObj->getValue();
        $currTime = time();
        // 进行数据处理
        foreach ($dataTypes as $type => $v) {
            /** @var RouteDataType $typeObj */
            $typeObj = $v['typeObj'];
            $model = $typeObj->getModel();
            $data = [
                'state' => $eventObj->getDbStateVal(),
                'last_update_time' => $currTime,
            ];
            $where = [
                ['id', 'in', $v['ids']],
                ['system_key', 'is null'],
                ['state', '=', $eventObj->getDbAllowDataStateVal()],
            ];
            if ($event == TableBuilderEvent::DELETED && ($tableUniqueKey = $typeObj->getTableUniqueKey())) {
                foreach ($tableUniqueKey as $uniqueKey) {
                    $data[$uniqueKey] = Db::raw("if(`{$uniqueKey}` is null,null,concat(`{$uniqueKey}`,'_del_{$currTime}'))");
                }
            }
            $typeObj->getModel()->change($data, $where);
        }
        // 重置路由
        RouteService::reset();
    }

    /**
     * 处理列表数据
     * @param array $items
     */
    private function handleListItems(array &$items): void {
        foreach ($items as &$item) {
            // name
            $name = "【{$item['type_txt']}】". handle_route_rule($item['name']);
            if (in_array($item['type'],[RouteDataType::REQUEST])) {
                $name .= '【' . ($item['method'] ?: 'ANY') . '】';
            }
            $item['name'] = $name;
            // base_url
            $baseUrl = '';
            list($type, $realId) = explode('_', $item['id']);
            if ($type == RouteDataType::ROUTE) {
                $routeData = RouteService::getRouteDataById($realId);
                $baseUrl = $routeData['base_url'] ?? '';
            }
            $item['base_url'] = $baseUrl;
            // url
            $item['url'] = $baseUrl;
        }
    }

    /**
     * 获取列表构建器表单条件
     * @param array $filter
     * @return array
     */
    private static function getListBuilderFilterWhere(array $filter): array {
        $state = $filter['state'];
        $ids = $filter['ids'];
        $keywords = $filter['keywords'] ?? '';
        $where = [
            ($state ? ['state', '=', $state] : ['state', '<>', State::DELETED]),
        ];
        if ($keywords) {
            if ($state == State::NORMAL) {
                // 获取匹配到的数据id和所有父级id集合
                $allIds = [];
                $allItems = RouteService::getAllItemsBuilderQuery()->where([['state', '=', State::NORMAL]])->select()->toArray();
                $matchIds = RouteService::getAllItemsBuilderQuery()->where([
                    ['state', '=', State::NORMAL],
                    ['name|route|base_url|full_desc', 'like', "%{$keywords}%"]
                ])->column('id');
                $allIds = [];
                foreach ($matchIds as $id) {
                    self::handleAllIdsByPid($allIds, $id, $allItems);
                }
                if ($allIds) {
                    $ids = array_merge($ids, $allIds);
                } else {
                    throw_empty_json();
                }
            } elseif ($state == State::RECYLE_BIN) {
                // 回收站
                $where[] = ['name|route|base_url|full_desc', 'like', "%{$keywords}%"];
            }
        }
        if ($ids) {
            $where[] = ['id', 'in', array_unique($ids)];
        }
        return $where;
    }

    // 获取所有父级ids
    private static function handleAllIdsByPid(array &$allIds, $pid, array $allItems) {
        $allIds[] = $pid;
        foreach ($allItems as $k => $item) {
            if ($item['id'] == $pid && $item['pid']) {
                self::handleAllIdsByPid($allIds, $item['pid'], $allItems);
                break;
            }
        }
    }

    /**
     * 设置列表构建器cols表头权限
     * @param array $cols
     */
    private function setListBuilderColsAuth(array &$cols): void {
        foreach ($cols as $k => $v) {
            $cols[$k]['auth'] = 'yunj_route_list_view_normal';
        }
    }

    /**
     * 获取列表构建器查询query数据表联合查询query
     * @return BaseQuery
     */
    public static function getListBuilderQuery() {
        $query = RouteService::getAllItemsBuilderQuery();
        // 不引入demo
        if (!yunj_config('admin.use_demo')) {
            $query->where('is_demo', '=', IsDemo::NO);
        }
        return $query;
    }


}